/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.stateless;

import entity.StakeholderEntity;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.ejb.Schedule;
import javax.ejb.SessionContext;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.mail.MessagingException;
import session.stateful.EmailSessionBean;
import session.stateful.ReportSessionBean;
import session.stateful.StakeholderSessionBeanStateful;
import session.stateful.TransactionSessionBean;


//Added by Cong Dat
import session.stateful.TransactionSessionBean;
import entity.GrouponEntity;
import entity.PurchasedGrouponEntity;
import entity.TransactionsEntity;
import entity.IssuedGrouponEntity;
import entity.TouristAccountEntity;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import session.stateful.GrouponSessionBean;
import com.paypal.sdk.core.nvp.NVPDecoder;
import com.paypal.sdk.core.nvp.NVPEncoder;
import com.paypal.sdk.profiles.APIProfile;
import com.paypal.sdk.profiles.ProfileFactory;
import com.paypal.sdk.services.NVPCallerServices;

// Added by Dat 27/10/2011
import entity.BranchEntity;
import entity.GrouponPaymentItemEntity;
import entity.PackagePurchasedEntity;
import entity.PackagePurchasedPaymentItemEntity;
import entity.PaymentManagementEntity;
import session.stateful.LoyaltyProgramSessionBean;
import entity.RedemptionListEntity;
import entity.ServicePackageEntity;
import session.stateful.BranchSessionBeanStateful;
import session.stateful.TouristSessionBean;
// Added by Dat 5/11/2011
import java.sql.Time;
/**
 *
 * @author HenryHieuPham
 */
@Stateless
@LocalBean
public class TimerSessionBean {

    @Resource
    private SessionContext ctx;
    @PersistenceContext
    private EntityManager entityManager;
    @EJB
    private EmailSessionBean emailSessionBean;
    @EJB
    private StakeholderSessionBeanStateful stakeholderSessionBean;
    @EJB
    private ReportSessionBean reportSessionBean;
    @EJB
    private TransactionSessionBean transactionSessionBean;
    @EJB
    private GrouponSessionBean grouponSessionBean;
    //added by Khanh Vu
    @EJB
    private BranchSessionBeanStateful branchSessionBean;
    //end added by Khanh Vu
    @EJB
    private TouristSessionBean touristSessionBean;
    private String hostIp;
    // Added by Cong Dat
    @EJB
    private LoyaltyProgramSessionBean loyaltyProgramSessionBean;


    @Schedule(hour = "21", minute = "25", second = "0")
    public void doSechedule() throws MessagingException {
        System.out.println("6");
        emailSessionBean.setPassword("emsongtronguocao");
        emailSessionBean.setUser("is3102team32");
        System.out.println("A");
        String subject = "Reset Password";
        String standardmsg = "Test";
        String recipient = "pttrunghieu@gmail.com";
        String from = "is3102team32@gmail.com";
        System.out.println("7");
        emailSessionBean.sendMail(from, recipient, subject, standardmsg);
        System.out.println("8");
    }

    @Schedule(hour = "16", minute = "02", second = "00")
    public void createBill() {
        Date date = new Date();

        List<StakeholderEntity> stakeholders = new ArrayList<StakeholderEntity>();
        stakeholders = stakeholderSessionBean.getAllStakeholders();

        System.out.println("This Already");
        if (!stakeholders.isEmpty()) {
            System.out.println("list not empty");
            for (Object o : stakeholders) {
                StakeholderEntity temp = (StakeholderEntity) o;
                if (temp.getBillingDay() == date.getDate()) {
                    System.out.println("Create bill and send email to " + temp.getCorpName());
                    //create PaymentManagement
                    transactionSessionBean.createPaymentManagement(temp);
                    //create Bill
                    System.out.println("Payment Management created");
                }
            }
        } else {
            System.out.println("empty");
        }

        //go through all branches and check for service package purchased. If it ends today
        //and the branch hasn't subsribe to new service package, change the package purchased
        //to free package.
        List<BranchEntity> branchList = branchSessionBean.getAllBranch();
        for (BranchEntity branch : branchList) {
            PackagePurchasedEntity current = branchSessionBean.getCurrentPackagePurchased(branch.getId());

            //if this branch hasn't subscribe to a service package. Switch it to Free Package
            if (current == null) {
                branchSessionBean.subscribeToFreeServicePackage(branch.getId());
            }

            //if today is billing day for this branch
            if (branch.getBillingDay() == date.getDate()) {
                current = branchSessionBean.getCurrentPackagePurchased(branch.getId());
                //TODO: create payment item;
                ServicePackageEntity pack = current.getServicePackage();
                if (!pack.getName().equals("Free Package") && !pack.getName().equals("Trial Package")) {
                    StakeholderEntity stakeholder = branch.getStakeholder();
                    PackagePurchasedPaymentItemEntity payment = new PackagePurchasedPaymentItemEntity();
                    payment.setPackagePurchased(current);
                    payment.setAmountToTCube(current.getPrice());
                    String explanation = "Subscription fee for using package " + pack.getName() 
                            + " in one month until " + date.getDate()+"/" + (date.getMonth()+1) + "/" + (date.getYear()+1900);
                    payment.setExplanation(explanation);
                    payment.setDateCreated(date);
                    payment.setStakeholder(stakeholder);
                    //set payment item to payment management
                    entityManager.persist(payment);
                    stakeholder.getPaymentItem().add(payment);
                    entityManager.merge(stakeholder);
                }
            }

        }
    }

    @Schedule(hour = "16", minute = "02", second = "20")
    public void createBill2() throws MessagingException, ClassNotFoundException, UnknownHostException {
        Date date = new Date();
        String message;
        message = "Pls view your bill";

        List<StakeholderEntity> stakeholders = new ArrayList<StakeholderEntity>();
        stakeholders = stakeholderSessionBean.getAllStakeholders();

        System.out.println("This Already");
        if (!stakeholders.isEmpty()) {
            System.out.println("list not empty");
            for (Object o : stakeholders) {
                StakeholderEntity temp = (StakeholderEntity) o;
                if (temp.getBillingDay() == date.getDate()) {
                    System.out.println("Create bill and send email to " + temp.getCorpName());
                    //create Bill
                    System.out.println("current bill" + transactionSessionBean.getCurrentBill(temp).getId());
                    reportSessionBean.createBill(temp, transactionSessionBean.getCurrentBill(temp));

                    //sendMail
                    emailSessionBean.setPassword("emsongtronguocao");
                    emailSessionBean.setUser("is3102team32");
                    String subject = "TCubeBill";
                    String standardmsg = message;
                    String recipient = temp.getCorpEmail();
                    System.out.println(temp.getCorpEmail());
                    String from = "is3102team32@gmail.com";
                    emailSessionBean.sendMail(from, recipient, subject, standardmsg);
                }
            }
        } else {
            System.out.println("empty");
        }
    }

    public void createTimers() {
        System.out.println("3");
        TimerService timerService = ctx.getTimerService();
        Timer timer5000ms = timerService.createTimer(5000, "EJBTIMER");
        System.out.println("4");
    }

    public void cancelTimers() {
        TimerService timerService = ctx.getTimerService();
        Collection timers = timerService.getTimers();
        for (Object obj : timers) {
            Timer timer = (Timer) obj;
            if (timer.getInfo().toString().equals("EJBTIMER")) {
                timer.cancel();
            }
        }
    }

    @Timeout
    public void handleTimeout(Timer timer) throws MessagingException {
        System.out.println("5");
        if (timer.getInfo().toString().equals("EJBTIMER")) {
            System.out.println("6");
            emailSessionBean.setPassword("emsongtronguocao");
            emailSessionBean.setUser("is3102team32");
            System.out.println("A");
            String subject = "Reset Password";
            String standardmsg = "Test";
            String recipient = "pttrunghieu@gmail.com";
            String from = "is3102team32@gmail.com";
            System.out.println("7");
            emailSessionBean.sendMail(recipient, subject, standardmsg, from);
            System.out.println("8");
        }
    }
    //Thai Duy

    public String getHostIp() throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();
        hostIp = inetAddress.getHostAddress();
        return hostIp;
    }

    @Schedule(hour = "23", minute = "59", second = "20")
    public void remindBill() throws MessagingException, ClassNotFoundException, UnknownHostException {
        Date date = new Date();
        String message;
        message = "Pls view and pay your bill";

        List<StakeholderEntity> stakeholders = new ArrayList<StakeholderEntity>();
        stakeholders = stakeholderSessionBean.getAllStakeholders();

        System.out.println("This Already");
        if (!stakeholders.isEmpty()) {
            System.out.println("list not empty");
            for (Object o : stakeholders) {
                StakeholderEntity temp = (StakeholderEntity) o;
                if (temp.getBillingDay() < date.getDate()) {
                    System.out.println("Check unpaid bill and send email to " + temp.getCorpName());
                    if(transactionSessionBean.getCurrentBill(temp)!=null){
                    //sendMail
                    emailSessionBean.setPassword("emsongtronguocao");
                    emailSessionBean.setUser("is3102team32");
                    String subject = "TCubeBill";
                    String standardmsg = message;
                    String recipient = temp.getCorpEmail();
                    System.out.println(temp.getCorpEmail());
                    String from = "is3102team32@gmail.com";
                    emailSessionBean.sendMail(from, recipient, subject, standardmsg);
                    }
                }
            }
        } else {
            System.out.println("empty");
        }
    }
    
    @Schedule(hour = "18", minute = "34", second = "0")
    public void testCreateTourist(){
        touristSessionBean.addTestTourist();
    }
    //Duy-end
    
    // Added by Cong Dat
    // 
    @Schedule(hour = "16", minute = "18", second = "00")
    public void processGroupon() throws MessagingException {
        // Gather all accepted groupon applications, check their startDate, if startDate = today then
        // set their status from "Application Successful" to "Deal is on"
        List<GrouponEntity> acceptedGrouponApplications = grouponSessionBean.getAllAcceptedGrouponApplications();
        GrouponEntity grouponApplication;
        Date today = new Date();
        Date grouponDate;
        for (int i = 0; i < acceptedGrouponApplications.size(); i++) {
            grouponApplication = acceptedGrouponApplications.get(i);
            grouponDate = grouponApplication.getStartDate();
            if (timeIgnoringComparator(today, grouponDate) == 0) {
                grouponApplication.setStatus("Deal is on");
                entityManager.merge(grouponApplication);
            }
        }
        // Gather all currently offered groupons, check their endDate, if endDate = today then
        // set their status from "Deal is on" to "Deal is off". After that, check whether the number of
        // purchases exceeds the minimum limit. If no, set deals to "not offered". Otherwise, "offered"
        List<GrouponEntity> currentlyOfferedGroupons = grouponSessionBean.getAllCurrentlyOfferedGrouponEntities();
        List<PurchasedGrouponEntity> purchasedGroupons;
        GrouponEntity groupon;

        for (int i = 0; i < currentlyOfferedGroupons.size(); i++) {
            groupon = currentlyOfferedGroupons.get(i);
            grouponDate = groupon.getEndDate();
            int numberOfPurchases = 0;
            if (timeIgnoringComparator(today, grouponDate) == 0) {
                numberOfPurchases = grouponSessionBean.getQuantityBought(groupon.getId());
                purchasedGroupons = groupon.getPurchasedGroupons();
                if (numberOfPurchases >= groupon.getMinimumIssuedQuantity()) {
                    // Issue groupons to successful tourists
                    grouponSessionBean.generateIssuedGroupons(groupon.getStakeholder().getId(), groupon.getId());
                    for (int j = 0; j < purchasedGroupons.size(); j++) {
                        PurchasedGrouponEntity temp = purchasedGroupons.get(j);
                        // Create a payment item 
                        GrouponPaymentItemEntity grouponPaymentItem = new GrouponPaymentItemEntity();
                        grouponPaymentItem.setAmountToStakeholder(temp.getQuantity() * groupon.getOfferedPrice() * (1 - groupon.getPercentCommissionSetByTCube() / 100));
                        grouponPaymentItem.setDateCreated(new Date());
                        grouponPaymentItem.setStakeholder(groupon.getStakeholder());
                        grouponPaymentItem.setPurchasedGroupon(temp);
                        grouponPaymentItem.setExplanation("This is the amount transfered to company " + groupon.getStakeholder().getCorpName() + " for their groupon's purchases");
                        entityManager.persist(grouponPaymentItem);
                        temp.setGrouponPaymentItem(grouponPaymentItem);
                        groupon.getStakeholder().getPaymentItem().add(grouponPaymentItem);
                        // Send an email to tourist, informing payment has been settled and attaching the groupons for them
                        System.out.println("before call send email method");
                        sendEmailToSuccessfulGrouponPurchaseTourists(temp.getId());
                    }
                } else {
                    for (int j = 0; j < purchasedGroupons.size(); j++) {
                        PurchasedGrouponEntity purchasedGroupon = purchasedGroupons.get(j);
                        purchasedGroupon.setStatus("Not Enough Purchases For The Deal");
                        entityManager.merge(purchasedGroupon);
                        // Refund to tourist
                        // 1. Get transaction
                        refundPayPal(purchasedGroupon.getTransactions().get(0));
                        // Email to them 
                    }
                }
                groupon.setStatus("Deal is over");
                entityManager.merge(groupon);
            }
        }
    }

    private void sendEmailToSuccessfulGrouponPurchaseTourists(Long purchasedGrouponId) {
        try {
            PurchasedGrouponEntity purchasedGroupon = entityManager.find(PurchasedGrouponEntity.class, purchasedGrouponId);
            String grouponList = "";
            for (int i = 0; i < purchasedGroupon.getQuantity(); i++) {
                grouponList = grouponList + "Groupon " + (i + 1) + " : " + purchasedGroupon.getIssuedGroupons().get(i).getReferenceNumber() + "\n";
            }
            String message = "Dear" + purchasedGroupon.getTourist().getTourist().getFirstName() + " " + purchasedGroupon.getTourist().getTourist().getLastName()
                    + ", \n\nThank you for purchasing on FoodSage.sg.\n\n"
                    + "This is to inform you that your groupon purchase on FoodSage.sg has been successful \n"
                    + "Here is your purchase details: \n"
                    + "Purchase reference number: " + purchasedGroupon.getConfirmationId() + "\n"
                    + "Groupon name: " + purchasedGroupon.getGroupon().getName() + "\n"
                    + "Groupon confirmation IDs :" + "\n"
                    + grouponList + "\n"
                    + "Remember that your groupon(s) will be valid from " + purchasedGroupon.getGroupon().getStartValidDate() + " to " + purchasedGroupon.getGroupon().getEndValidDate() + ".\n"
                    + "Also, don't forget to visit our website to enjoy many other great deals and promotions offered.\n"
                    + "Have a nice day. \n\n FoodSage.sg. ";
            emailSessionBean.setUser("is3102team32@gmail.com");
            emailSessionBean.setPassword("emsongtronguocao");
            emailSessionBean.sendMail("is3102team32@gmail.com", purchasedGroupon.getTourist().getTourist().getEmail(), "FoodSage.sg Groupon Purchase Reference for "
                    + purchasedGroupon.getTourist().getTourist().getFirstName() + " " + purchasedGroupon.getTourist().getTourist().getLastName(), message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void refundPayPal(TransactionsEntity transaction) {
        try {
            String paypalTransactionId = null;
            String paypalCorrelationId = null;
            org.apache.log4j.BasicConfigurator.configure();

            Double amount = transaction.getPurchasedGroupon().getQuantity() * transaction.getPurchasedGroupon().getGroupon().getOfferedPrice();
            String note = "Refund for groupon purchase " + transaction.getPurchasedGroupon().getConfirmationId();

            paypalTransactionId = transaction.getPaypalTransactionId();
            NVPDecoder paypalResponse = RefundTransactionCode("Partial", paypalTransactionId, String.valueOf(amount), note);
            // ack variable
            boolean success = false;
            String response = "";
            String statusMessage = "";

            for (Object objKey : paypalResponse.getMap().keySet()) {
                System.out.println(objKey.toString() + " = " + paypalResponse.getMap().get(objKey));

                if (objKey.toString().equals("L_LONGMESSAGE0")) {
                    statusMessage = (String) paypalResponse.getMap().get(objKey);
                }

                // Ack is a success
                if (objKey.toString().equals("ACK")) {
                    response = (String) paypalResponse.getMap().get(objKey);
                    if (response.equals("Success")) {
                        success = true;
                    }
                }
                if (objKey.toString().equals("REFUNDTRANSACTIONID")) {
                    paypalTransactionId = (String) paypalResponse.getMap().get(objKey);
                }
                if (objKey.toString().equals("CORRELATIONID")) {
                    paypalCorrelationId = (String) paypalResponse.getMap().get(objKey);
                }
            }
            // transaction successful
            if (success == true) {
                // create payment record
                TransactionsEntity refundTransaction = new TransactionsEntity();
                refundTransaction.setAmount(-1 * amount);
                refundTransaction.setPaypalCorrelationId(paypalCorrelationId);
                refundTransaction.setPaypalTransactionId(paypalTransactionId);
                refundTransaction.setPurchasedGroupon(transaction.getPurchasedGroupon());
                refundTransaction.setTourist(transaction.getTourist());
                // Added by Cong Dat
                refundTransaction.setDatePaid(new Date());
                refundTransaction.setTimePaid(new Time(System.currentTimeMillis()));
                refundTransaction.setDescription(note);
                
                // Duy check dum anh xem trong entity Transactions co field nao de record cai type cua transaction ko
                // Neu co them vao dong o duoi
                // refundTransaction.setType("REFUND");
                entityManager.persist(refundTransaction);
                List<TransactionsEntity> tempList = transaction.getTourist().getTransactions();
                tempList.add(refundTransaction);
                transaction.getTourist().setTransactions(tempList);
                //transactionSessionBean.createTransaction(-1*amount, "REFUND", paypalTransactionId, paypalCorrelationId, 
                //        transaction.getTourist(), transaction.getReservation(), transaction.getStakeholder(), transaction.getPaymentManagement());
                System.out.println("Refund Successful");
                // Email tourist about the refund
                String message = "Dear" + transaction.getTourist().getTourist().getFirstName() + " " + transaction.getTourist().getTourist().getLastName()
                        + ", \n\nThank you for purchasing on FoodSage.sg.\n\n"
                        + "This is to inform you that your groupon purchase on FoodSage.sg has been unsuccessful due to not having sufficient number of purchases required.\n"
                        + "Therefore, the amount you paid to us has been refunded. \n"
                        + "Here is the refund detail: \n"
                        + "Purchase reference number: " + transaction.getPurchasedGroupon().getConfirmationId() + "\n"
                        + "Groupon name: " + transaction.getPurchasedGroupon().getGroupon().getName() + "\n"
                        + "We are really sorry for any inconvenience caused \n"
                        + " Meanwhile, don't forget to visit our website to enjoy many other great deals and promotions offered. "
                        + " Your participation is very important to us. \n"
                        + "Have a nice day. \n\nFoodSage.sg.";
                emailSessionBean.setUser("is3102team32@gmail.com");
                emailSessionBean.setPassword("emsongtronguocao");
                emailSessionBean.sendMail("is3102team32@gmail.com", transaction.getTourist().getTourist().getEmail(), "FoodSage.sg Groupon Purchase Refund For "
                        + transaction.getTourist().getTourist().getFirstName() + " " + transaction.getTourist().getTourist().getLastName(), message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public NVPDecoder RefundTransactionCode(String refundType, String transactionId, String amount, String note) {
        NVPEncoder encoder = new NVPEncoder();
        NVPDecoder decoder = new NVPDecoder();
        NVPCallerServices caller = null;

        try {
            caller = new NVPCallerServices();
            APIProfile profile = ProfileFactory.createSignatureAPIProfile();
            /*
            WARNING: Do not embed plaintext credentials in your application code.
            Doing so is insecure and against best practices.
            Your API credentials must be handled securely. Please consider
            encrypting them for use in any production environment, and ensure
            that only authorized individuals may view or modify them.
             */

            // Set up your API credentials, PayPal end point, API operation and version.
            profile.setAPIUsername("web_1316757704_biz_api1.gmail.com");
            profile.setAPIPassword("1316757754");
            profile.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AobkBjpaOfK5wRRDT34RrVAP6RfZ");
            profile.setEnvironment("sandbox");
            profile.setSubject("");
            caller.setAPIProfile(profile);
            encoder.add("VERSION", "60.0");
            encoder.add("METHOD", "RefundTransaction");

            // Add request-specific fields to the request string.
            encoder.add("REFUNDTYPE", refundType);
            encoder.add("TRANSACTIONID", transactionId);
            if ((refundType != null) && (refundType.length() > 0) && (refundType.equalsIgnoreCase("Partial"))) {
                encoder.add("AMT", amount);
            }
            encoder.add("NOTE", note);

            // Execute the API operation and obtain the response.
            String NVPRequest = encoder.encode();
            String NVPResponse = (String) caller.call(NVPRequest);
            decoder.decode(NVPResponse);
        } catch (Exception ex) {

            ex.printStackTrace();
        }
        return decoder;
    }

    private int timeIgnoringComparator(Date d1, Date d2) {
        if (d1.getYear() != d2.getYear()) {
            return d1.getYear() - d2.getYear();
        }
        if (d1.getMonth() != d2.getMonth()) {
            return d1.getMonth() - d2.getMonth();
        }
        return d1.getDate() - d2.getDate();
    }
    // Added by Cong Dat
    // 
    @Schedule(hour = "00", minute = "00", second = "00")
    public void processULPItem() throws MessagingException {
        // Gather all accepted ULP Item applications, check their startDate, if startDate = today then
        // set their status from "Application Successful" to "Deal is on"
        List<RedemptionListEntity> acceptedULPItemApplications = loyaltyProgramSessionBean.getAcceptedULPItemApplications();
        RedemptionListEntity ULPItemApplication;
        Date today = new Date();
        Date ULPItemDate;
        for (int i = 0; i < acceptedULPItemApplications.size(); i++) {
            ULPItemApplication = acceptedULPItemApplications.get(i);
            ULPItemDate = ULPItemApplication.getValidFrom();
            if (timeIgnoringComparator(today, ULPItemDate) == 0) {
                ULPItemApplication.setStatus("Deal is on");
                entityManager.merge(ULPItemApplication);
            }
        }
        // Gather all currently offered ULP Items, check their endDate, if endDate = today then
        // set their status from "Deal is on" to "Deal is off". 
        List<RedemptionListEntity> currentlyOfferedULPItems = loyaltyProgramSessionBean.getAllCurrentULPItemEntities();
        RedemptionListEntity ULPItem;
        for (int i = 0; i < currentlyOfferedULPItems.size(); i++) {
            ULPItem = currentlyOfferedULPItems.get(i);
            ULPItemDate = ULPItem.getValidUntil();
            if (timeIgnoringComparator(today, ULPItemDate) == 0) {
                ULPItem.setStatus("Expired");
                entityManager.merge(ULPItem);
            }
        }
    }
}
